﻿#region using...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
#endregion

namespace Infusion.Silverlight.Controls.Menu
{
    #region : Menu :
    #region TemplateParts...
    [TemplatePart(Name = Menu.MenuLayoutRoot, Type = typeof(Canvas))]
    [TemplatePart(Name = Menu.AnimateVisibility, Type = typeof(Storyboard))]
    [TemplatePart(Name = Menu.VisibilityAnimation, Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = Menu.RectBackgroundShadow, Type = typeof(Rectangle))]
    [TemplatePart(Name = Menu.RectBackground, Type = typeof(Rectangle))]
    [TemplatePart(Name = Menu.RectIconBorder, Type = typeof(Rectangle))]
    [TemplatePart(Name = Menu.LineIconBorder, Type = typeof(Line))]
    [TemplatePart(Name = Menu.LineIconBorderClip, Type = typeof(RectangleGeometry))]
    [TemplatePart(Name = Menu.SkPnlMenuItems, Type = typeof(StackPanel))]
    [TemplatePart(Name = Menu.GridResizeBar, Type = typeof(Grid))]
    [TemplatePart(Name = Menu.CanvasResizeBar, Type = typeof(Canvas))]
    [TemplatePart(Name = Menu.LineResizeBarBorder, Type = typeof(Line))]
    [TemplatePart(Name = Menu.RectResizeBarBorderClip, Type = typeof(RectangleGeometry))]
    [TemplatePart(Name = Menu.ImgDragVertical, Type = typeof(Image))]
    [TemplatePart(Name = Menu.ImgDragBoth, Type = typeof(Image))]
    #endregion
    [ContentProperty("MenuItems")]
    public class Menu : Control
    {
        #region Events...
        public event EventHandler Closing;
        #endregion

        #region TemplatePart Names...
        public const string MenuLayoutRoot = "MenuLayoutRoot";
        public const string AnimateVisibility = "AnimateVisibility";
        public const string VisibilityAnimation = "VisibilityAnimation";
        public const string RectBackgroundShadow = "RectBackgroundShadow";
        public const string RectBackground = "RectBackground";
        public const string RectIconBorder = "RectIconBorder";
        public const string LineIconBorder = "LineIconBorder";
        public const string LineIconBorderClip = "LineIconBorderClip";
        public const string SkPnlMenuItems = "SkPnlMenuItems";
        public const string GridResizeBar = "GridResizeBar";
        public const string CanvasResizeBar = "CanvasResizeBar";
        public const string LineResizeBarBorder = "LineResizeBarBorder";
        public const string RectResizeBarBorderClip = "RectResizeBarBorderClip";
        public const string ImgDragVertical = "ImgDragVertical";
        public const string ImgDragBoth = "ImgDragBoth";
        #endregion

        #region TemplatePart Variables...
        internal Canvas menuLayoutRoot;
        internal Storyboard animateVisibility;
        internal DoubleAnimation visibilityAnimation;
        internal Rectangle rectBackgroundShadow;
        internal Rectangle rectBackground;
        internal Rectangle rectIconBorder;
        internal Line lineIconBorder;
        internal RectangleGeometry lineIconBorderClip;
        internal StackPanel skPnlMenuItems;
        internal Grid gridResizeBar;
        internal Canvas canvasResizeBar;
        internal Line lineResizeBarBorder;
        internal RectangleGeometry rectResizeBarBorderClip;
        internal Image imgDragVertical;
        internal Image imgDragBoth;
        #endregion

        #region Class Variables...
        private bool templateApplied = false;
        private bool animatingVisibility = false;
        private bool initialLayoutUpdatedEvent = false;
        private bool forceRedraw = false;
        private bool showIconBorder = true;
        private MenuItem parentMenuItem = null;
        private double overallHeight = 0;
        private double maxHeight = 0;
        private double maxWidth = 0;
        private int resizeableIMenuItemIndex = -1;
        #endregion

        #region Dependency Properties...
        #region MenuItemsProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Menu.Menu.MenuItems dependency property.
        /// </summary>
        public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register(
                "MenuItems",
                typeof(MenuItemCollection),
                typeof(Menu),
                null);
        #endregion

        #region IDProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Menu.Menu.ID dependency property.
        /// </summary>
        public static readonly DependencyProperty IDProperty = DependencyProperty.Register(
                "ID",
                typeof(string),
                typeof(Menu),
                null);
        #endregion
        #endregion

        #region Constructor(s)...
        #region Menu
        public Menu() : base()
        {
            DefaultStyleKey = typeof(Menu);
            SetValue(Control.IsTabStopProperty, true);

            MenuItems = new MenuItemCollection();
        }
        #endregion
        #endregion

        #region Event Handlers...
        #region menuLayoutRoot_LayoutUpdated
        private void menuLayoutRoot_LayoutUpdated(object sender, EventArgs e)
        {
            if (initialLayoutUpdatedEvent || forceRedraw)
            {
                MenuListViewResizeDirection resizeDirection = MenuListViewResizeDirection.None;
                //if (resizeableIMenuItemIndex != -1)
                //{
                //    resizeDirection = ((MenuListView)menuItemCollection[resizeableIMenuItemIndex]).ResizeDirection;
                //}

                double currentYOffset = 2;
                overallHeight = 4;

                maxHeight = 0;
                maxWidth = 0;

                foreach (IMenuItem menuItem in skPnlMenuItems.Children)
                {
                    menuItem.ParentMenu = this;

                    if (resizeableIMenuItemIndex == -1)
                    {
                        double nextWidth = menuItem.RealWidth;

                        if (nextWidth > maxWidth)
                            maxWidth = nextWidth;
                    }
                    else
                    {
                        //maxWidth = menuItemCollection[resizeableIMenuItemIndex].RealWidth;
                    }

                    double nextHeight = menuItem.RealHeight;

                    if (nextHeight > maxHeight)
                        maxHeight = nextHeight;

                    overallHeight += nextHeight;

                    menuItem.YOffset = currentYOffset;
                    currentYOffset += nextHeight;
                }

                rectBackground.Width = maxWidth + 3;
                rectBackgroundShadow.Width = maxWidth + 3;
                rectBackground.Height = overallHeight + (resizeDirection != MenuListViewResizeDirection.None ? 11 : 0);
                rectBackgroundShadow.Height = overallHeight;

                foreach (IMenuItem iMenuItem in skPnlMenuItems.Children)
                {
                    switch (iMenuItem.GetType().ToString())
                    {
                        case "Infusion.Silverlight.Controls.Menu.MenuItem":
                            {
                                MenuItem menuItem = (MenuItem)iMenuItem;
                                menuItem.menuItemLayoutRoot.ColumnDefinitions[1].Width = new GridLength(maxWidth - lineIconBorder.X1);
                                break;
                            }
                        case "Infusion.Silverlight.Controls.Menu.MenuSeparator":
                            {
                                MenuSeparator separator = (MenuSeparator)iMenuItem;
                                separator.lineSeparator.X2 = maxWidth - lineIconBorder.X1;

                                separator.lineSeparatorClip.Rect = new Rect(separator.lineSeparatorClip.Rect.X,
                                    separator.lineSeparatorClip.Rect.Y,
                                    maxWidth - lineIconBorder.X1,
                                    separator.lineSeparatorClip.Rect.Height);
                                break;
                            }
                    }
                }

                rectIconBorder.Visibility = showIconBorder ? Visibility.Visible : Visibility.Collapsed;
                lineIconBorder.Visibility = showIconBorder ? Visibility.Visible : Visibility.Collapsed;

                if (showIconBorder)
                {
                    lineIconBorderClip.Rect = new Rect(lineIconBorderClip.Rect.X,
                        lineIconBorderClip.Rect.Y,
                        lineIconBorderClip.Rect.Width,
                        overallHeight - 2);

                    rectIconBorder.Height =
                        lineIconBorder.Y2 = overallHeight - 2;
                }

                if (resizeDirection != MenuListViewResizeDirection.None)
                {
                    gridResizeBar.Visibility = Visibility.Visible;
                    gridResizeBar.SetValue(Canvas.TopProperty, currentYOffset + 1);
                    gridResizeBar.Width = maxWidth - 1;

                    switch (resizeDirection)
                    {
                        case MenuListViewResizeDirection.Vertical:
                            imgDragVertical.Visibility = Visibility.Visible;
                            break;
                        case MenuListViewResizeDirection.Both:
                            imgDragBoth.Visibility = Visibility.Visible;
                            break;
                    }

                    lineResizeBarBorder.X2 = maxWidth - 1;
                    rectResizeBarBorderClip.Rect = new Rect(0, 0, maxWidth - 1, 1);
                }

                if (!forceRedraw)
                {
                    Visibility = Visibility.Collapsed;
                    menuLayoutRoot.Opacity = 0.0;
                }

                initialLayoutUpdatedEvent = false;
                forceRedraw = false;
            }
        }
        #endregion

        #region animateVisibility_Completed
        private void animateVisibility_Completed(object sender, EventArgs e)
        {
            animatingVisibility = false;

            if (menuLayoutRoot.Opacity == 0.0d)
            {
                SetValue(Canvas.LeftProperty, -5000d);
                SetValue(Canvas.TopProperty, -5000d);
                Visibility = Visibility.Collapsed;
            }
        }
        #endregion
        #endregion

        #region Methods...
        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (!templateApplied)
            {
                menuLayoutRoot = (Canvas)GetTemplateChild(MenuLayoutRoot);
                animateVisibility = (Storyboard)GetTemplateChild(AnimateVisibility);
                visibilityAnimation = (DoubleAnimation)GetTemplateChild(VisibilityAnimation);
                rectBackgroundShadow = (Rectangle)GetTemplateChild(RectBackgroundShadow);
                rectBackground = (Rectangle)GetTemplateChild(RectBackground);
                rectIconBorder = (Rectangle)GetTemplateChild(RectIconBorder);
                lineIconBorder = (Line)GetTemplateChild(LineIconBorder);
                lineIconBorderClip = (RectangleGeometry)GetTemplateChild(LineIconBorderClip);
                skPnlMenuItems = (StackPanel)GetTemplateChild(SkPnlMenuItems);
                gridResizeBar = (Grid)GetTemplateChild(GridResizeBar);
                canvasResizeBar = (Canvas)GetTemplateChild(CanvasResizeBar);
                lineResizeBarBorder = (Line)GetTemplateChild(LineResizeBarBorder);
                rectResizeBarBorderClip = (RectangleGeometry)GetTemplateChild(RectResizeBarBorderClip);
                imgDragVertical = (Image)GetTemplateChild(ImgDragVertical);
                imgDragBoth = (Image)GetTemplateChild(ImgDragBoth);

                menuLayoutRoot.LayoutUpdated += new EventHandler(menuLayoutRoot_LayoutUpdated);
                animateVisibility.Completed += new EventHandler(animateVisibility_Completed);

                foreach (IMenuItem menuItem in MenuItems)
                {
                    skPnlMenuItems.Children.Add((UIElement)menuItem);
                }

                initialLayoutUpdatedEvent = true;
                templateApplied = true;
            }
        }
        #endregion

        #region Show
        public void Show(bool useAnimation, Point menuPosition)
        {
            if (Visibility == Visibility.Collapsed)
            {
                if (!animatingVisibility)
                {
                    animatingVisibility = true;

                    Visibility = Visibility.Visible;
                    visibilityAnimation.From = 0;
                    visibilityAnimation.To = 1;
                    visibilityAnimation.Duration = new Duration(new TimeSpan(0, 0, 0, 0, useAnimation ? 500 : 0));

                    SetValue(Canvas.LeftProperty, menuPosition.X);
                    SetValue(Canvas.TopProperty, menuPosition.Y);

                    animateVisibility.Begin();

                    Focus();
                }
            }
        }
        #endregion

        #region Hide
        public void Hide(bool closeParent)
        {
            animateVisibility.Stop();
            animatingVisibility = true;

            visibilityAnimation.From = 1;
            visibilityAnimation.To = 0;
            visibilityAnimation.Duration = new TimeSpan(0, 0, 0, 0, 300);

            //parent...
            if (ParentMenuItem != null)
            {
                //ParentMenuItem.SubMenuOpen = false;
                //ParentMenuItem.RectHighlight.Visibility = Visibility.Collapsed;

                if (closeParent)
                {
                    //if (ParentMenuItem.ParentMenu != null)
                    //    ParentMenuItem.ParentMenu.Hide(closeParent);
                }
            }

            //children...
            foreach (IMenuItem iMenuItem in MenuItems)
            {
                if (iMenuItem.GetType() == typeof(MenuItem))
                {
                    MenuItem menuItem = (MenuItem)iMenuItem;
                    //if (menuItem.SubMenuOpen && menuItem.Menu != null)
                    //{
                    //    menuItem.Menu.Hide(false);
                    //}
                }
            }

            animateVisibility.Begin();

            if (Closing != null)
                Closing(this, null);
        }
        #endregion
        #endregion

        #region Properties...
        #region ID
        public string ID
        {
            get { return (string)GetValue(IDProperty); }
            set { SetValue(IDProperty, value); }
        }
        #endregion

        #region MenuItems
        public MenuItemCollection MenuItems
        {
            get { return (MenuItemCollection)GetValue(MenuItemsProperty); }
            set { SetValue(MenuItemsProperty, value); }
        }
        #endregion

        #region ParentMenuItem
        public MenuItem ParentMenuItem
        {
            get { return parentMenuItem; }
            set { parentMenuItem = value; }
        }
        #endregion

        #region RealWidth
        public double RealWidth
        {
            get { return rectBackground.Width; }
        }
        #endregion
        #endregion
    }
    #endregion

    #region : MenuItemCollection :
    public class MenuItemCollection : ObservableCollection<IMenuItem>
    {
    }
    #endregion
}